/*
	Copyright 2009 Jason Nottingham

	This program is free software: you can redistribute it and/or modify
	it under the terms of the GNU Lesser General Public License as published by
	the Free Software Foundation, either version 3 of the License, or
	(at your option) any later version.

	This program is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
	GNU Lesser General Public License for more details.

	You should have received a copy of the GNU Lesser General Public License
	along with this program.  If not, see <http://www.gnu.org/licenses/>.


    How to submit a patch:
    1. create or modify a test case (under 'tests') so that it fails to compile/link/run without 
       your change
    2. verify you have the latest sources (resync/merge)
    3. fix or add the missing functionality
    4. verify that your changes fixes the newly broken test case in #1 - it now builds and runs 
       C++ the same as the original C#
    5. create a Subversion-friendly diff or patch file of your changes (including the test cases)
    6. submit your patch at http://gonative.codeplex.com


*/

#include "BasicDataTypes.h"

WCHAR *__goNative_DupAscii( const char *c )
{
	if ( !c )
		return NULL;

	int i = strlen(c);
	int chars = i + 1;
	WCHAR *wc = (WCHAR*)malloc( chars * sizeof(WCHAR) );
	if ( wc )
		StringCchPrintf( wc, chars, L"%S", c );
	return wc;
}

CHAR *__goNative_DupWCHAR( const WCHAR *wc )
{
	if ( !wc )
		return NULL;

	int i = wcslen(wc);
	int chars = i + 1;
	CHAR *c = (CHAR*)malloc( chars );
	if ( c )
		StringCchPrintfA( c, chars, "%S", wc );
	return c;
}

string::string()
{
	initialize();
	// printf( "this 0x0%x, wcValue 0x0%x, line %d\n", this, wcValue, __LINE__ );
}

string::string( const WCHAR *wc )
{
	initialize();
	if ( wc )
		wcValue = _wcsdup( wc );
	// printf( "this 0x0%x, wcValue 0x0%x, line %d\n", this, wcValue, __LINE__ );
}

string::string( const CHAR *c )
{
	initialize();
	if ( c )
		wcValue = __goNative_DupAscii( c );
	// printf( "this 0x0%x, wcValue 0x0%x, line %d\n", this, wcValue, __LINE__ );
}

string::string( const string &copy_from )
{
	initialize();
	wcValue = wcsdup( copy_from.wcValue );
	// printf( "this 0x0%x, wcValue 0x0%x, line %d\n", this, wcValue, __LINE__ );
}

string::string( int i )
{
	initialize();
	Append_int( i );
}

string::string( double d )
{
	initialize();
	Append_double( d );
}

string::~string()
{
	// printf( "DTOR this 0x0%x, wcValue 0x0%x, line %d\n", this, wcValue, __LINE__ );
	FreeValues();
	// printf( "\n" );
}

void string::copy_from( WCHAR *wc )
{
	FreeValues();
	wcValue = _wcsdup( wc );
}

void string::copy_from( string s )
{
	FreeValues();
	wcValue = _wcsdup( s.ToString() );
}

const WCHAR *string::ToString()
{
	return wcValue;
}

const CHAR *string::ToAscii()
{
	if ( !szValue )
		szValue = __goNative_DupWCHAR( wcValue );
	return szValue;
}


List<string> *string::Split( char delimiter )
{
	WCHAR wc[2] = { delimiter, NULL };
	string s(wc);
	return Split(s);
}

List<string> *string::Split( string delimiter )
{
	List<string> *answer = new List<string>();
	WCHAR *wcCopy = _wcsdup( wcValue );
	WCHAR *wc = wcCopy;
	WCHAR *wcNext = NULL;
	WCHAR *wcDelimiter = (WCHAR*)delimiter.ToString();
	int count = 0;

	while( wcNext = wcsstr( wc, wcDelimiter ) )
	{
		*wcNext = 0;
		answer->Add( wc );
		wc = wcNext+1;
		count++;
	}
	if ( *wc )
	{
		answer->Add( wc );
		count++;
	}

	if ( count == 0 )
		answer->Add( wcCopy );

	free( wcCopy );
	return answer;
}


int string::LastIndexOf( string text )
{
	const WCHAR *wc = text.ToString();
	if ( string::IsNullOrEmpty(wc) )
		return -1;

	WCHAR *found = wcValue;
	WCHAR *last = NULL;

	while( found = wcsstr( found, wc ) )
		last = found++;

	if ( last == NULL )
		return -1;

	return (int)( last - wcValue );
}

int string::IndexOf( string text )
{
	const WCHAR *wc = text.ToString();
	if ( string::IsNullOrEmpty(wc) )
		return -1;

	WCHAR *found = (WCHAR*)wcsstr( wc, wcValue );

	if ( found == NULL )
		return -1;

	return (int)( found - wcValue );
}


string string::Replace( string find, string replace )
{
	WCHAR *wcFind = (WCHAR*)find.ToString();
	WCHAR *wcReplace = (WCHAR*)replace.ToString();
	WCHAR *wcCopy = wcsdup( wcValue );
	WCHAR *wc = wcCopy;
	int iFind = wcslen(wcFind);
	int iReplace = wcslen(wcReplace);

	if ( iFind == iReplace )
	{
		while( wc = wcsstr( wc, wcFind ) )
			wcsncpy( wc, wcReplace, iReplace );
	}
	else if ( iFind < iReplace )
	{
		// BUGBUG - need to handle expanding the string!
		assert( !"not written yet!" );
	}
	else
	{
		// need to shorten the string as we go
		while( wc = wcsstr( wc, wcFind ) )
		{
			wcsncpy( wc, wcReplace, iReplace );
			wcscpy( wc+iReplace, wc+iFind );
		}
	}

	string result(wcCopy);
	return result;
}